#include "udpserv.h"

// 客户端不应该写成一发一收的形式，如果在服务器多转发数据的时候时，客户端只有发完消息以后才能收到消息
// 所以为客户端创建多线程形式，一个负责专门发消息，一个负责专门收消息

void reciever(const u_int16_t &sockfd)
{
    while (1)
    {
        // 收消息
        char buffer[default_size];
        struct sockaddr_in other; // 是一个输入输出型参数，接收消息以后会存入发消息的主机信息
        socklen_t len = sizeof(other);
        ssize_t m = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (sockaddr *)&other, &len); // 收消息(来自于服务端)
        Inet_addr tmp(other);
        if (m > 0)
        {
            buffer[m] = 0;
            tmp.print_client_info(buffer); // 打印发送方的相关ip端口信息
        }
    }
}
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        cout << "格式错误\n正确格式:" << argv[0] << " ip"
             << " port" << endl;
    }
    string ip = argv[1];
    uint16_t port = atoi(argv[2]);

    // 1.创建套接字（本质就是创建文件细节）
    u_int16_t sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        lg.Log_infom(Fatal, "创建套接字失败: sockfd=%d,%s", sockfd, strerror(errno));
        exit(-1);
    }
    lg.Log_infom(Fatal, "创建套接字成功: sockfd=%d", sockfd);

    // 不需要显式bind绑定，客户端发送消息的时候会自动绑定随机端口与当前ip

    // 服务端套接字信息配置
    struct sockaddr_in server;
    server.sin_family = AF_INET;                    // socket inet(ip) 协议家族,绑定网络通信的信息
    server.sin_port = htons(port);                  // 将主机端口号转成网络
    server.sin_addr.s_addr = inet_addr(ip.c_str()); // 转成网络序列的四字节ip

    // 创建收消息的线程
    thread reciev(reciever, sockfd);

    while (1)
    {
        string info;
        //cout << "please enter:";
        getline(cin, info);
        ssize_t n = sendto(sockfd, info.c_str(), info.size(), 0, (sockaddr *)&server, sizeof(server));// 发消息给server服务端（此时会绑定好相关套接字信息）
        if(n<=0) 
            cout<<"发送消息失败"<<endl;
    }
    reciev.join();

    return 0;
}